package com.cqhfan.imservice.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqhfan.api.clients.user.UserClient;
import com.cqhfan.core.enums.ChatTypeEnum;
import com.cqhfan.core.exceptions.BizException;
import com.cqhfan.core.utils.UserContext;
import com.cqhfan.imservice.mapper.ChatGroupMapper;
import com.cqhfan.imservice.mapper.ChatListMapper;
import com.cqhfan.imservice.mapper.ImMessageMapper;
import com.cqhfan.imservice.service.ChatListService;
import com.cqhfan.imservice.service.ImMessageService;
import com.cqhfan.pojo.im.dto.UnReadMessageDTO;
import com.cqhfan.pojo.im.po.ChatGroup;
import com.cqhfan.pojo.im.po.ChatList;
import com.cqhfan.pojo.im.po.ImMessage;
import com.cqhfan.pojo.im.vo.ChatListVO;
import com.cqhfan.pojo.user.po.User;
import com.cqhfan.redis.constants.RedisConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 眭传洪
 * @create 2025-08-17 0:05
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChatListServiceImpl extends ServiceImpl<ChatListMapper, ChatList> implements ChatListService {

    private final ChatGroupMapper chatGroupMapper;

    private final UserClient userClient;

    private final ImMessageService imMessageService;

    private final ImMessageMapper imMessageMapper;

    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public String createPrivateChatItem(ChatList body) {
        Long userId = UserContext.getUser();
        Long receiverId = body.getReceiverId();

        // 单聊只需要保存我自己的就可以了
        ChatList chatList = lambdaQuery()
                .eq(ChatList::getUserId, userId)
                .eq(ChatList::getReceiverId, receiverId)
                .eq(ChatList::getType, ChatTypeEnum.SINGLE.getValue())
                .one();
        if (chatList == null) {
            body.setUserId(userId);
            body.setCreateTime(LocalDateTime.now());
            save(body);
        }
        return chatList != null ? chatList.getId().toString() : body.getId().toString();
    }

    @Override
    public ChatListVO getSingleChatInfo(Long receiveUserId) {
        // 返回接收人的信息
        List<User> users = userClient.listByIds(Collections.singletonList(receiveUserId));
        if (CollUtil.isEmpty(users)) {
            throw new BizException("获取接收人信息失败");
        }
        User user = users.get(0);
        ChatListVO result = new ChatListVO();
        result.setAvatar(user.getAvatar());
        result.setReceiverId(user.getId());
        result.setLastMessageNickName(user.getNickName());
        return result;
    }

    @Override
    public List<ChatListVO> listChatList() {
        // 分页查询我的聊天列表数据
        Long userId = UserContext.getUser();
        List<ChatList> chatLists = lambdaQuery()
                .eq(ChatList::getUserId, userId)
                .or()
                .eq(ChatList::getReceiverId, userId)
                .list();
        if (CollUtil.isEmpty(chatLists)) {
            return Collections.emptyList();
        }

        // 获取群聊数据
        List<Long> groupIds = chatLists.stream()
                .filter(item -> item.getType() == ChatTypeEnum.MULTI)
                .map(ChatList::getGroupId)
                .toList();
        Map<Long, ChatGroup> groupMap = Collections.emptyMap();
        if (CollUtil.isNotEmpty(groupIds)) {
            List<ChatGroup> groups = chatGroupMapper.selectBatchIds(groupIds);
            groupMap = groups.stream().collect(Collectors.toMap(ChatGroup::getId, cg -> cg));
        }

        // 根据聊天项的id拿到最新的消息
        List<Long> chatListIds = chatLists.stream().map(ChatList::getId).toList();
        List<ImMessage> messages = imMessageService.lambdaQuery()
                .in(ImMessage::getChatListId, chatListIds)
                .orderByDesc(ImMessage::getCreateTime)
                .last("limit 1")
                .list();
        Map<Long, ImMessage> messageMap = Collections.emptyMap();
        if (CollUtil.isNotEmpty(messages)) {
            messageMap = messages.stream().collect(Collectors.toMap(ImMessage::getChatListId, m -> m));
        }

        // 统计各个消息列表未读消息数
        Map<Long, Integer> unReadMessageQuantityMap = getUnReadQuantityMap(chatLists, userId);

        // 获取用户信息
        Set<Long> userIds = new HashSet<>();
        for (ChatList chatList : chatLists) {
            userIds.add(chatList.getUserId());
            userIds.add(chatList.getReceiverId());
        }
        Map<Long, User> userMap = Collections.emptyMap();
        if (CollUtil.isNotEmpty(userIds)) {
            List<User> users = userClient.listByIds(userIds);
            userMap = users.stream().collect(Collectors.toMap(User::getId, u -> u));
        }

        // 组装VO
        List<ChatListVO> result = new ArrayList<>(chatLists.size());
        for (ChatList chatList : chatLists) {
            // 聊天列表信息设置
            Long chatListId = chatList.getId();
            ImMessage message = messageMap.get(chatListId);
            if (message == null) {
                continue;
            }
            ChatListVO vo = new ChatListVO();
            result.add(vo);
            vo.setId(chatListId);
            ChatTypeEnum type = chatList.getType();
            vo.setType(type.getValue());

            // 设置聊天数据
            if (type == ChatTypeEnum.SINGLE) {
                // 单聊设置备注和头像
                Long senderUserId = chatList.getUserId();
                // 如果发送者不是当前登录用户，说明创建的时候我是做为接收者的，所以，此时正确的接收者是发送者
                Long messageUserId = NumberUtil.equals(userId, senderUserId) ? chatList.getReceiverId() : senderUserId;
                User user = userMap.get(messageUserId);
                if (user != null) {
                    vo.setReceiverId(messageUserId);
                    vo.setAvatar(user.getAvatar());
                    vo.setLastMessageNickName(user.getNickName());
                }
            } else {
                // 设置群聊基本信息
                Long groupId = chatList.getGroupId();
                ChatGroup chatGroup = groupMap.get(chatList.getGroupId());
                if (chatGroup != null) {
                    vo.setGroupId(groupId);
                    vo.setGroupName(chatGroup.getGroupName());
                    vo.setAvatar(chatGroup.getGroupAvatar());
                }
                // 设置最后一个发消息的用户昵称
                Long senderId = message.getSenderId();
                User user = userMap.get(senderId);
                if (user != null) {
                    vo.setLastMessageNickName(user.getNickName());
                }
            }
            vo.setLastMessageTime(chatList.getCreateTime());
            vo.setLastMessageContent(message.getContent());
            vo.setLastMessageTime(message.getCreateTime());
            vo.setUnReaderMessageNums(unReadMessageQuantityMap.get(chatListId));
        }

        // 按照消息时间降序排列
        result.sort(Comparator.comparing(ChatListVO::getLastMessageTime).reversed());
        return result;
    }

    private Map<Long, Integer> getUnReadQuantityMap(List<ChatList> chatLists, Long userId) {
        // 获取单聊
        List<Long> singleChatListIds = new ArrayList<>(chatLists.size());
        List<Long> multiChatListIds = new ArrayList<>(chatLists.size());
        List<Long> groupIds = new ArrayList<>(chatLists.size());
        for (ChatList chatList : chatLists) {
            if (chatList.getType() == ChatTypeEnum.SINGLE) {
                singleChatListIds.add(chatList.getId());
            } else {
                multiChatListIds.add(chatList.getId());
                groupIds.add(chatList.getGroupId());
            }
        }
        List<UnReadMessageDTO> countDTOs = imMessageMapper.countUnReadMessage(singleChatListIds);

        // 获取群聊
        List<Object> objects = stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            StringRedisConnection stringRedisConnection = (StringRedisConnection) connection;
            for (Long groupId : groupIds) {
                String key = RedisConstants.IM.GROUP_MESSAGE_UNREAD_QUANTITY_KEY_PREFIX + groupId;
                stringRedisConnection.hGet(key, userId.toString());
            }
            return null;
        });

        // 处理群聊并转换map
        for (int i = 0; i < multiChatListIds.size(); i++) {
            UnReadMessageDTO messageDTO = new UnReadMessageDTO();
            messageDTO.setChatListId(multiChatListIds.get(i));
            Object obj = objects.get(i);
            messageDTO.setUnReadQuantity(obj == null ? 0 : Integer.parseInt(obj.toString()));
            countDTOs.add(messageDTO);
        }
        return countDTOs.stream().collect(Collectors.toMap(UnReadMessageDTO::getChatListId,
                UnReadMessageDTO::getUnReadQuantity));
    }

    @Override
    public void updateCurrentChatRoomReadStatus(Long chatListId) {
        // 更新数据库下所有的消息的未读
        ChatList chatList = getById(chatListId);
        String key = RedisConstants.IM.UPDATE_CURRENT_CHAT_LIST_KEY;
        Long userId = UserContext.getUser();
        if (chatList == null) {
            // 这里查不到代表不在聊天页面，直接删除当前登录用户的chatListId
            stringRedisTemplate.opsForHash().delete(key, userId.toString());
            return;
        }

        // 拿到当前进入窗口的实际用户 如果登录用户就是当前聊天框的userId代表是创建人，否则就是接收人
        Long chatListUserId = chatList.getUserId();
        userId = NumberUtil.equals(userId, chatListUserId) ? chatListUserId : chatList.getReceiverId();

        if (chatList.getType() == ChatTypeEnum.SINGLE) {
            // 单聊才需要更新
            imMessageService.lambdaUpdate()
                    .eq(ImMessage::getChatListId, chatListId)
                    .set(ImMessage::getIfRead, Boolean.TRUE)
                    .update();
        } else {
            // 群聊直接把当前用户的值干掉
            String unreadKey = RedisConstants.IM.GROUP_MESSAGE_UNREAD_QUANTITY_KEY_PREFIX + chatList.getGroupId();
            stringRedisTemplate.opsForHash().delete(unreadKey, userId.toString());
        }

        // 直接设置redis的值就可以了
        stringRedisTemplate.opsForHash().put(key, userId.toString(), chatListId.toString());
    }

}
